package com.anquing.securitydemo.filter.phonecode;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;

/**
 * @author wangqq65
 * @since 2021/8/17 15:01
 */
public class PhoneCodeAuthenticationProvider implements AuthenticationProvider {

    protected final Log logger = LogFactory.getLog(getClass());

    private UserDetailsService userDetailsService;

    public void setUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    protected UserDetailsService getUserDetailsService() {
        return this.userDetailsService;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername((String) authentication.getPrincipal());
        if (loadedUser == null) {
            this.logger.debug("Failed to authenticate since no not found user");
            throw new InternalAuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation");
        }

        if (authentication.getCredentials() == null) {
            this.logger.debug("Failed to authenticate since no credentials provided");
            throw new BadCredentialsException("AbstractUserDetailsAuthenticationProvider.badCredentials");
        }

        // 检验验证码(这部分也可以抽取成filter)
        String code = authentication.getCredentials().toString();
        if (!"123456".equals(code)) {
            this.logger.debug("Failed to authenticate since code does not match stored value");
            throw new BadCredentialsException("AbstractUserDetailsAuthenticationProvider.badCredentials");
        }
        PhoneCodeAuthenticationToken phoneCodeAuthenticationToken = new PhoneCodeAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), loadedUser.getAuthorities());
        phoneCodeAuthenticationToken.setDetails(authentication.getDetails());

        return phoneCodeAuthenticationToken;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return (PhoneCodeAuthenticationToken.class.isAssignableFrom(authentication));
    }
}
